//    Copyright (C) Kherty.  All rights reserved.
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.IO;
using OpenLS.Spreadsheet.Expressions;
using OpenLS.Spreadsheet.Functions;

namespace OpenLS.Spreadsheet.Formats.Biff.Tokens
{
    internal class FunctionVarToken : FunctionTokenBase
    {

        public FunctionVarToken(AccessorType type): base(type)
        {
        }

        public FunctionVarToken(AccessorType type, BuiltInFunctionId functionId, int argumentCount): base (type, functionId)
        {
            Contract.Requires(functionId != BuiltInFunctionId.ISERROR);
            this.argumentCount = argumentCount;
            isBuiltIn = true;
        }

        public override FormulaTokenId TokenId
        {
            get { switch (_type)
            {
            case AccessorType.Array:
                    return FormulaTokenId.FuncVarA;
            case AccessorType.Reference:
                    return FormulaTokenId.FuncVar;
                    case AccessorType.Value:
                    return FormulaTokenId.FuncVarV;
                default: throw new NotSupportedException();
            }
            }
        }
        private int argumentCount;
        private bool prompt;
        protected bool isBuiltIn;

        public override ushort GetLength(FormulaReadContextType formulaReadContextType)
        {
            return 3;
        }

        internal override void ReadContent(FormulaReadContext context)
        {
            byte b = context.ReadByte();
            argumentCount = (b & 0x7F);
            prompt = (b & 0x80) != 0;
            ushort ui = context.ReadUInt16();
            this._functionId = (BuiltInFunctionId) (ui & 0x7FFF);
            isBuiltIn = (ui & 0x8000) == 0;
        }
        public override void WriteContent(FormulaWriteContext context)
        {
            byte b = (byte) argumentCount;
            if (prompt)
                b |= 0x80;
            context.Writer.Write(b);
            ushort ui = (ushort) _functionId;
            if (!isBuiltIn)
                ui |= 0x8000;
            context.WriteUInt16(ui);

            
        }

        internal override Expression GetExpression(FormulaEvaluationContext context)
        {
            int count = argumentCount;
            if (_functionId == BuiltInFunctionId.Custom)
                count--;
            var arguments = new List<Expression>();
            for (int i = 0; i < count; i++)
            {
                FormulaToken token = context.PoppedArgument();
                arguments.Add(token.GetExpression(context));
            }
            arguments.Reverse();
            string name;
            if (_functionId == BuiltInFunctionId.Custom)
            {
                FormulaToken t = context.PoppedArgument();
                if (t is NameXToken)
                {
                    var nameToken = (NameXToken) t;
                    name = nameToken.GetDefinedName(context.WorkbookContext); //\\
                         
                    //name = context.WorkbookContext.ExternalNames[nameToken.NameId - 1];
                }
                else
                {
                    var nameToken = (NameToken) t;
                    name = nameToken.GetDefinedName(context.WorkbookContext).Name;
                    
                }
            }
            else
                name = _functionId.ToString();
            Function fn = context.Workbook.Document.Context.GetFunction(name, false);
            if (fn == null)
                fn = new UnknownFunction(name);
            return new FunctionInvokeExpression(fn, arguments, context.Workbook.Document.Context);
        }
    }
}